#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "driver/uart.h"
#include "string.h"

#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "ble_spp_server_demo.h"

//add
#include "ble_data_handle.h"
#include "esp_partition.h"
#include "flash.h"
#include "driver/gpio.h"
#include "gpio.h"

#define ESP_INTR_FLAG_DEFAULT 0

xQueueHandle led_queue = NULL;
xQueueHandle gpio_evt_queue = NULL;

static void IRAM_ATTR gpio_isr_handler(void *arg)
{
    uint32_t gpio_num = (uint32_t)arg;
    xQueueSend(gpio_evt_queue, &gpio_num, NULL);
}

static void led_task(void *arg)
{
    /*
        [0] 效果类型：LED_EVENT_TWINKLE
        [1] 选择LED：LED_2/LED_3
        [2] 结束后状态：1/0
    */
    uint8_t typed[3];

    for (;;)
    {
        if (xQueueReceive(led_queue, typed, portMAX_DELAY))
        {
            switch (typed[0])
            {
            case LED_EVENT_TWINKLE:
                gpio_set_level(typed[1], typed[2]);
                vTaskDelay(300 / portTICK_PERIOD_MS);
                gpio_set_level(typed[1], !typed[2]);
                vTaskDelay(300 / portTICK_PERIOD_MS);
                gpio_set_level(typed[1], typed[2]);
                vTaskDelay(300 / portTICK_PERIOD_MS);
                gpio_set_level(typed[1], !typed[2]);
                vTaskDelay(300 / portTICK_PERIOD_MS);
                gpio_set_level(typed[1], typed[2]);
                break;
            default:
                break;
            }
        }
    }
}

void gpio_init()
{
    gpio_config_t io_conf;

    //disable interrupt
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = (1 << LED_2) | (1 << LED_3) | (1 << CTRL1) | (1 << CTRL2) | (1 << BUZZER);
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);

    //disable interrupt
    io_conf.intr_type = GPIO_PIN_INTR_NEGEDGE;
    //set as output mode
    io_conf.mode = GPIO_MODE_INPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = (1 << BUTTON_1) | (1 << BUTTON_2);
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 1;
    //configure GPIO with the given settings
    gpio_config(&io_conf);

    //create a queue to handle gpio event from isr
    gpio_evt_queue = xQueueCreate(5, sizeof(uint32_t));

    //install gpio isr service
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(BUTTON_1, gpio_isr_handler, (void *)BUTTON_1);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(BUTTON_2, gpio_isr_handler, (void *)BUTTON_2);

    gpio_set_level(LED_2, 1);
    gpio_set_level(LED_3, 1);
    gpio_set_level(CTRL1, 0);
    gpio_set_level(CTRL2, 0);
    gpio_set_level(BUZZER, 0);

    led_queue = xQueueCreate(1, sizeof(uint8_t) * 3);

    xTaskCreate(led_task, "led_task", 1024 * 1, NULL, 2, NULL);
}
